package com.miku.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.miku.annotation.AuthCheck;
import com.miku.common.BaseResponse;
import com.miku.common.DeleteRequest;
import com.miku.common.ErrorCode;
import com.miku.common.ResultUtils;
import com.miku.constant.UserConstant;
import com.miku.exception.BusinessException;
import com.miku.exception.ThrowUtils;
import com.miku.model.dto.credit.CreditAddRequest;
import com.miku.model.dto.credit.CreditUpdateRequest;
import com.miku.model.entity.Credit;
import com.miku.model.entity.User;
import com.miku.service.CreditService;
import com.miku.service.UserService;
import com.miku.utils.RedissonLockUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

import static com.miku.constant.CreditConstant.CREDIT_CACHE_KEY;
import static com.miku.constant.CreditConstant.DAILY_CHECK;

@Api(tags = "积分系统")
@RestController
@RequestMapping("/credit")
@Slf4j
public class CreditController {

    @Resource
    private CreditService creditService;
    @Resource
    private UserService userService;
    @Resource
    private RedissonLockUtil redissonLockUtil;
    /**
     * 添加图表信息
     *
     * @param creditAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add")
    @ApiOperation("添加积分信息")
    public BaseResponse<Long> addCredit(@RequestBody CreditAddRequest creditAddRequest, HttpServletRequest request) {
        if (creditAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Credit credit = new Credit();
        BeanUtils.copyProperties(creditAddRequest, credit);
        User loginUser = userService.getLoginUser(request);
        credit.setUserId(loginUser.getId());
        boolean result = creditService.save(credit);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        long newCreditId = credit.getId();
        return ResultUtils.success(newCreditId);
    }

    /**
     * 删除图表信息
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete")
    @ApiOperation("删除积分信息")
    public BaseResponse<Boolean> deleteCredit(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User user = userService.getLoginUser(request);
        long id = deleteRequest.getId();
        // 判断是否存在
        Credit oldCredit = creditService.getById(id);
        ThrowUtils.throwIf(oldCredit == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可删除
        if (!oldCredit.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        boolean b = creditService.removeById(id);
        return ResultUtils.success(b);
    }

    /**
     * 更新图表信息（仅管理员）
     *
     * @param creditUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @ApiOperation("更新积分信息")
    public BaseResponse<Boolean> updateCredit(@RequestBody CreditUpdateRequest creditUpdateRequest) {
        if (creditUpdateRequest == null || creditUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Credit Credit = new Credit();
        BeanUtils.copyProperties(creditUpdateRequest, Credit);
        long id = creditUpdateRequest.getId();
        // 判断是否存在
        Credit oldCredit = creditService.getById(id);
        ThrowUtils.throwIf(oldCredit == null, ErrorCode.NOT_FOUND_ERROR);
        boolean result = creditService.updateById(Credit);
        return ResultUtils.success(result);
    }

    /**
     * 根据  获取,总计积分信息
     *
     * @return
     */
    @GetMapping("/get")
    @ApiOperation("获取当前登录用户的积分信息")
    public BaseResponse<Long> getCreditVOById(HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        long userId = loginUser.getId();
        if (userId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Credit credit = creditService.getOne(Wrappers.<Credit>lambdaQuery().eq(Credit::getUserId, userId));
        if (credit == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }

        return ResultUtils.success(credit.getCreditTotal());
    }

    @GetMapping("/sign")
    @ApiOperation("每日签到")
    public Boolean signUser(HttpServletRequest httpServletRequest) {
        User loginUser = userService.getLoginUser(httpServletRequest);
        Long userId = loginUser.getId();
        if (userId == null){
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        String lockName= "credit_sign_lock:"+userId;
        //使用分布式锁
     return   redissonLockUtil.redissonDistributedLocks(lockName,()->{
            QueryWrapper<Credit> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("userId", userId);
            Credit credit = creditService.getOne(queryWrapper);
            ThrowUtils.throwIf(credit == null, ErrorCode.NOT_FOUND_ERROR);
            //判断今天是否已经签过
            if (DateUtil.isSameDay(credit.getUpdateTime(), new DateTime())) {
                return false;
            }
            Long creditTotal = credit.getCreditTotal() + DAILY_CHECK;
            credit.setCreditTotal(creditTotal);
            //保持更新时间
            credit.setUpdateTime(null);
            return creditService.updateById(credit);
        },"签到失败");
    }









}
